前端面霸:一文搞懂虚拟DOM

您所在的位置:网站首页 js 删除dom节点 前端面霸:一文搞懂虚拟DOM

前端面霸:一文搞懂虚拟DOM

2023-04-28 16:03| 来源: 网络整理| 查看: 265

一、虚拟 DOM

在React框架中,虚拟 DOM 是由 React.createElement() 或 JSX 语法创建的 JavaScript 对象。

当应用程序的状态发生更改时,它可以在内存中构建新的 DOM 树,与旧的 DOM 树进行比较,以确定需要进行哪些 DOM 操作来更新应用程序的界面。

工作原理

虚拟 DOM 的工作原理分为三个步骤:

生成虚拟 DOM 树 比较新旧虚拟 DOM 树以查找差异 根据差异更新实际 DOM 元素

React框架使用一种叫做 "diff算法" 的优化算法来查找差异,并使用 "批处理" 技术将多个 DOM 更新操作合并为单个操作来优化性能。

Hello World React Vue // 经过转化后,长这样: { type: 'div', props: { class: 'Index' }, children: [ { type: 'div', children: 'Hello World' }, { type: 'ul', children: [ { type: 'li', children: 'React' }, { type: 'li', children: 'Vue' }, ] } ] } 复制代码

在React框架中,每个虚拟DOM节点都有以下属性:

type: 节点的类型,例如元素节点、文本节点等。 ref: 节点的引用,用于在React中直接访问DOM节点。 key: 用于帮助React区分不同的子元素,以提高更新性能。 props: 节点的属性,例如元素节点的class、id等属性。 children: 包含节点的子节点的数组,其中子节点可以是其他虚拟DOM节点,也可以是文本节点。如果一个节点没有子节点,则其children属性为空数组。 $$typeof: React使用的一个特殊属性,用于标识该节点是一个合法的React元素,而不是普通的JavaScript对象。 二、与真实 DOM 对比

通过各自的创建方式,以打印的方式检查两种 DOM 的区别:

const VDOM = React.createElement('div', {}, 'Hello VDOM') const DOM = document.createElement("div"); DOM.innerHTML = 'Hello DOM' console.log(`虚拟DOM:`, VDOM) console.log(`真实DOM:`, DOM) 复制代码 数据结构不同 虚拟 DOM 是 JavaScript 对象 而真实 DOM 是浏览器内部维护的一种数据结构。 操作方式不同 虚拟 DOM 的操作是在 JavaScript 环境下进行的,操作通常不会引起页面的重绘和重排 而真实 DOM 的操作是在浏览器环境下进行的,操作很可能会引起页面的重绘和重排 更新方式不同 虚拟 DOM 更新时,会先生成新的虚拟 DOM 树,然后通过比较新旧虚拟 DOM 树的差异来更新真实 DOM 而真实 DOM 更新时,每次修改都会立即更新 DOM 树 三、虚拟 DOM 的优点 提高性能:浏览器处理 DOM 很慢,处理 JS 对象很快 。 使用虚拟 DOM,可以避免频繁地对实际 DOM 进行操作,从而减少浏览器的重绘和回流,提高应用程序的性能和效率。 简化开发:原生JS很多时候要关注 DOM 操作,对于虚拟 DOM 开发者只需要关注数据和状态的变化,而不必考虑如何手动更新 DOM 。React 会负责一切与 DOM 相关的操作,包括处理事件、调整布局、更新样式等。 跨平台:由于虚拟 DOM 只是一个 JavaScript 对象,因此它可以在不同的平台上运行,例如Web、iOS 和 Android 等。这使得开发人员可以在不同的平台上使用相同的代码库,并且只需根据需要使用不同的渲染器即可。

综上所述,虚拟 DOM 可以提高性能、简化开发、跨平台和方便测试等方面的优点,使得现代 Web 应用程序开发更加高效和可靠。

一定能提升性能吗

不一定!

虚拟 DOM 的性能优势主要在于能够减少实际 DOM 的操作次数。但是,如果应用程序本身的复杂度不高或者虚拟DOM的实现方式不够优秀,可能无法带来性能提升,甚至会引入额外的性能开销。

它的优势是在于 diff 算法和批量处理策略,将所有的 DOM 操作搜集起来,一次性去改变真实的 DOM ,但在首次渲染上,虚拟 DOM 会多了一层计算,消耗一些性能,所以有可能会比 html 渲染的要慢

总之,虚拟DOM在适当的情况下可以提高性能,但并不是一定能够提升性能,需要根据实际情况进行评估。

四、diff 算法

diff 算法是指在比较两棵虚拟DOM树时,通过一系列的算法来计算出它们之间的差异,然后只更新需要更新的部分,从而减少对实际DOM的操作,提高性能和效率。

降低 diff 算法复杂度

React 中的 diff 算法并非首创,而是引入,React团队为 diff 算法做出了质的优化:

在计算一颗树转化为另一颗树有哪些改变时,传统的 diff 算法通过循环递归对节点进行依此对比,算法复杂度达到 O(n^ 3) ,也就是说,如果展示一千个节点,就要计算十亿次。

而 Reac t中的 diff 算法,算法复杂度为 O(n) ,即展示一千个节点,只需要计算一千次。

React通过三种策略完成了优化

Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略不计。 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构。 对于同一层级的一组子节点,它们可以通过唯一 id 进行区分。

分别对应:tree diff(同级比较)、component diff(组件比较)、element diff(节点比较)

当应用程序的状态发生变化时,虚拟DOM会在内存中构建新的虚拟DOM树,并与之前的虚拟DOM树进行比较,以找出它们之间的差异,然后只更新需要更新的部分,从而提高应用程序的性能和效率。这个过程称为 “协调” 。

Tree diff

tree diff 是虚拟 DOM 协调过程中的一种算法,用于查找并比较新旧虚拟DOM树之间的差异。它通过深度优先遍历虚拟DOM树,并逐个比较节点来查找差异,并标记需要更新的部分,从而提高应用程序的性能和效率。

Component diff

Component diff算法的实现方式与tree diff算法类似,都是采用深度优先遍历的方式来遍历虚拟DOM树。但是,Component diff算法比tree diff算法更加复杂,因为它不仅要比较虚拟DOM节点之间的差异,还要比较组件的状态和属性。在比较组件时,React会根据组件类型和key值来确定它们是否相同,从而决定是否需要更新组件。

element diff

Element diff算法的实现方式比Component diff算法更加简单,它只需要比较同一层级的子节点之间的key值,以确定它们的位置是否有变化。如果子节点的位置没有变化,则只需要比较其它属性是否有变化,并更新需要更新的部分。如果子节点的位置有变化,则需要将原来的子节点移动到新的位置,而不是创建一个新的子节点。

五、虚拟DOM面试题

01 | 虚拟DOM是如何提高应用程序性能的?

提高性能的本质都是为了:减少操作真实 DOM 以减少性能消耗, 方法有两类:

通过将 DOM 操作转换为对 JavaScript 对象的操作 因为真实 DOM 的操作会引起页面的重绘和重排,这是非常消耗性能的。而虚拟 DOM 操作只需要更新 JavaScript 对象,不会引起页面的重绘和重排。 通过 diff 算法等优化策略 在更新虚拟 DOM 树时,会通过 diff 算法比较新旧虚拟DOM树的差异,只更新需要更新的部分,从而减少对真实DOM的操作次数。 虚拟 DOM 还使用批处理技术,将多个DOM操作合并为单个操作,从而进一步提高性能。

批处理:需要进行多次DOM操作,批处理技术可以将这些操作合并为单个操作,从而减少对真实DOM的操作次数,提高性能和效率。

02 | 为什么处理DOM慢,而处理对象快?

浏览器处理 DOM 很慢的原因主要有以下几点:

DOM 操作会引起页面的重绘和重排,这是非常消耗性能的。每次对 DOM 进行修改都需要重新计算布局和重新绘制元素,这个过程非常耗费时间。 DOM 结构是树形结构,它需要通过遍历来查找和访问节点。当 DOM 结构非常庞大时,遍历的时间成本也会相应增加。 DOM 操作涉及到网络请求和 I/O 操作,这些操作通常是异步执行的,需要等待操作完成后才能进行下一步操作。这也会影响到 DOM 操作的性能。

相比之下,JS处理对象要快一些的原因主要有以下几点:

JS 引擎通常会将对象存储在堆内存中,并使用指针来访问它们。因为堆内存是连续的,所以访问对象的时间复杂度是常数级别的,而不会像 DOM 遍历那样需要花费大量时间。 JS 引擎在对对象进行操作时,通常会将其存储在寄存器或缓存中,这样可以大大提高访问速度。 JS 的对象通常比DOM结构更小,这意味着访问和操作对象所需的数据量更少,也更容易缓存。

总之,浏览器处理 DOM 很慢,而 JS 处理对象很快的原因主要在于 DOM 操作涉及到页面布局和渲染等复杂的计算和 I/O 操作,而 JS 操作对象通常只需要访问内存中的指针,并且对象的大小和操作数据量都比 DOM 结构小。

03 | 什么是key值?在React中,为什么需要使用key值?

在 React 中,key 是用来标识列表中每个子元素的唯一标识符。当使用列表渲染(如 'map()' 方法)时,React 会根据每个子元素的 key 值来进行优化,从而提高列表的渲染性能和效率。

React 使用 key 来追踪哪些子元素被修改、添加或删除。当进行列表更新时,React 会首先使用 key 来判断新旧子元素是否相同,从而减少对真实 DOM 的操作。如果没有 key,React 只能通过比较子元素的内容和顺序来判断子元素是否相同,这样会增加 React 的运算负担,降低应用程序的性能。

需要注意的是,key 值必须是唯一的,并且稳定不变的。如果列表中的 key 值发生变化,React 会认为该子元素已经被删除,而不是被更新,这样可能会导致不必要的性能损失。

因此,在使用 key 时,应该选择一个稳定不变的值,如子元素的唯一标识符或索引值。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3